#include "Including.h"


using namespace std;

//if the collada file is loaded correctly
string collada_flat = "ok"; 

namespace Collada
{

	int MyCollada::ColladaReader(const char* pFilename, struct COLLADA *colladafile)
	{

		TiXmlDocument doc(pFilename);
		bool loadOkay = doc.LoadFile();
		if (!loadOkay) 
		{
			cout<< "Could not load collada file" <<endl;
			collada_flat = "wrong";
			return 0;
		}

		struct Source s[10];
		struct Float_Array f[10];
		struct Accessor a[10];
		struct Param p[10];
		struct Vertices v[10];
		struct Input in[10];
		struct Triangles tri[10];
		struct P pp[10];

		colladafile->m_GeometryLibrary = (struct GeometryLibrary *) malloc (sizeof (struct GeometryLibrary) * 1);
		colladafile->m_GeometryLibrary[0].m_Geometries = (struct Geometry *) malloc (sizeof (struct Geometry) * 20);

		//Get dom elements of collada xml file   
		TiXmlElement* collada = doc.RootElement(); //Collada
		TiXmlElement* library_geometries = collada->FirstChildElement( "library_geometries" ); 
		TiXmlElement* geometry = library_geometries->FirstChildElement("geometry");
		
		//Geometry
		int geo = 0;
		for(;geometry; geometry = geometry->NextSiblingElement("geometry"))
		{

		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh =  (struct Mesh *) malloc (sizeof (struct Mesh) * 1);
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources = (struct Source *) malloc (sizeof (struct Source) * 20);
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices = (struct Vertices *) malloc (sizeof (struct Vertices) * 1);
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles = (struct Triangles *) malloc (sizeof (struct Triangles) * 20);

		TiXmlElement* mesh = geometry->FirstChildElement("mesh");
		TiXmlElement* source = mesh->FirstChildElement("source");
		//Source
		int i = 0;
		for(;source; source = source->NextSiblingElement("source"))
		{
			TiXmlAttribute *source_id = source->FirstAttribute(); //source_id
			s[i].m_ID = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_ID = _strdup(source_id->Value());
			//cout<< i << ": " << s[i].m_ID <<endl;

			//memory allocation
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array = (struct Float_Array *) malloc (sizeof (struct Float_Array) * 1);
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Name_Array = (struct Name_Array *) malloc (sizeof (struct Name_Array) * 1);
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon = (struct Technique_Common *) malloc (sizeof (struct Technique_Common) * 1);

			//float_array
			TiXmlElement* float_array = source->FirstChildElement("float_array");
			TiXmlAttribute *float_id = float_array->FirstAttribute(); //float_array id: m_ID
			f[i].m_ID = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array[0].m_ID = _strdup(float_id->Value());
			//cout<< i << ": " <<f[i].m_ID <<endl;

			TiXmlAttribute *float_count = float_array->FirstAttribute()->Next(); //float_array count: m_Count
			f[i].m_Count = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array[0].m_Count = atoi(float_count->Value());
			//cout<< i << ": " <<f[i].m_Count <<endl;

			string value = float_array->ToElement()->GetText(); //float_array value: m_Floats
			f[i].m_Floats = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array[0].m_Floats = new double[f[i].m_Count];
			int index = 0;
			stringstream strstm(value);
			while (strstm>>f[i].m_Floats[index]){ ++index; }
			//cout<<i<<": "<<f[i].m_Floats[0]<<endl;


			//technique_common
			TiXmlElement* technique_common = source->FirstChildElement("technique_common"); 
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor = (struct Accessor *) malloc (sizeof (struct Accessor) * 1);

			//accessor
			TiXmlElement* accessor = technique_common->FirstChildElement("accessor");
			TiXmlAttribute *a_source = accessor->FirstAttribute(); //accessor source
			a[i].m_Source = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Source = _strdup(a_source->Value());
			TiXmlAttribute *a_count = a_source->Next(); //accessor count
			a[i].m_Count = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Count = atoi(a_count->Value());
			TiXmlAttribute *a_stride = a_count->Next(); //accessor stride
			a[i].m_Stride = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Stride = atoi(a_stride->Value());
			//cout<< i << ": " <<a[i].m_Source << " "<< a[i].m_Count <<" "<<a[i].m_Stride<<endl;

			//param
			TiXmlElement* param = accessor->FirstChildElement("param");
			int x = 0;
			for(;param; param = param->NextSiblingElement("param"))
			{
				TiXmlAttribute *p_name = param->FirstAttribute(); //param name
				colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Params = (struct Param *) malloc (sizeof (struct Param) * 3);
				p[x].m_Name = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Params[x].m_Name = _strdup(p_name->Value());
				TiXmlAttribute *p_type = p_name->Next(); //param type
				p[x].m_Type = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Params[x].m_Type = _strdup(p_type->Value());
				//cout<< x << ": "<< p[x].m_Name << " " <<p[x].m_Type<<endl;
				x++;
			}

			i++; //source number
		}
		//how many sources
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].number_sources = i;
		

		//vertices
		TiXmlElement* vertices = mesh->FirstChildElement("vertices");
		TiXmlAttribute *id = vertices->FirstAttribute(); //vertice id
		v[0].m_ID = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_ID = _strdup(id->Value());
		//cout<< v[0].m_ID <<endl; 

		//input
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_Inputs = (struct Input *) malloc (sizeof (struct Input) * 1);
		TiXmlElement* input = vertices->FirstChildElement("input");
		TiXmlAttribute *sem = input->FirstAttribute(); //input semantic
		in[0].m_Semantic = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_Inputs[0].m_Semantic = _strdup(sem->Value());
		//cout<< in[0].m_Semantic <<endl;
		TiXmlAttribute *sour = sem->Next(); //input source
		in[0].m_Source = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_Inputs[0].m_Source = _strdup(sour->Value());
		//cout<< in[0].m_Source <<endl;
		//cout<<endl;


		//triangles
		TiXmlElement* triangles = mesh->FirstChildElement("triangles");
		int number_t = 0;
		for(;triangles; triangles = triangles->NextSiblingElement("triangles"))
		{
			TiXmlAttribute *material = triangles->FirstAttribute(); //triangle material
			tri[number_t].m_Material = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Material = _strdup(material->Value());
			TiXmlAttribute *count = triangles->FirstAttribute()->Next(); //triangle count
			tri[number_t].m_Count = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Count = atoi(count->Value());
			//cout<< tri[number_t].m_Material << " " << tri[number_t].m_Count <<endl;

			//input
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs = (struct Input *) malloc (sizeof (struct Input) * 10);
			TiXmlElement* input2 = triangles->FirstChildElement("input");
			int y = 0;
			for(;input2; input2 = input2->NextSiblingElement("input"))
			{
				TiXmlAttribute *in_Semantic = input2->FirstAttribute(); //input semantic
				in[y].m_Semantic = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs[y].m_Semantic = _strdup(in_Semantic->Value());
				
				TiXmlAttribute *in_Source = in_Semantic->Next(); //input source
				in[y].m_Source = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs[y].m_Source = _strdup(in_Source->Value());

				TiXmlAttribute *in_Offset = in_Source->Next(); //input offset
				in[y].m_Offset = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs[y].m_Offset = _strdup(in_Offset->Value());

				//cout<<in[y].m_Semantic<<" "<<in[y].m_Source<<" "<<in[y].m_Offset<<endl;

				if(in_Offset->Next()){
					TiXmlAttribute *in_Set = in_Offset->Next(); //input set
					in[y].m_Set = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs[y].m_Set = _strdup(in_Set->Value());
					//cout<<in[y].m_Set<<endl;
				}
				y++;
			}
			//how many inputs in a triangle
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].number_inputs = y;

			//p
			colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_p = (struct P *) malloc (sizeof (struct P) * 1);
			TiXmlElement* sp = triangles->FirstChildElement("p");

			string p_value = sp->ToElement()->GetText(); //P value: m_Indices
			pp[number_t].m_Indices = colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_p[0].m_Indices = new unsigned short[tri[number_t].m_Count * (3 * y)];
			int index_p = 0;
			stringstream strstm(p_value);
			while (strstm>>pp[number_t].m_Indices[index_p]){ ++index_p; }
			//cout<<number_t<<": "<<pp[number_t].m_Indices[0]<<endl;
			//cout<<index_p<<endl;

			number_t ++;
		}
		//how many triangles in mesh
		colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].number_triangles = number_t;

		geo ++; 
		} //geometry
		//how many geometrices in geometry library
		colladafile->m_GeometryLibrary[0].number_geometrices = geo;

		//release TiXmlDocument
		doc.Clear();

		return 1;
	}


	//release memory
	void MyCollada::FreeCollada (struct COLLADA *colladafile)
	{

		if (colladafile->m_GeometryLibrary[0].m_Geometries)
		{
			//free geometrices
			for(int geo = 0; geo < colladafile->m_GeometryLibrary[0].number_geometrices; geo++)
			{
				//free sources
				for(int i = 0; i < colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].number_sources; i++)
				{
					delete colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array[0].m_Floats;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Float_Array = NULL;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Name_Array);	
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_Name_Array = NULL;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Params);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor[0].m_Params = NULL;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon[0].m_Accessor = NULL;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources[i].m_TechniqueCommon = NULL;
				}
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Sources = NULL;


				//free vertices
				free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_Inputs);
				colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices[0].m_Inputs = NULL;
				free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices);
				colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Vertices = NULL;

				//free triangles
				for(int number_t = 0; number_t < colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].number_triangles; number_t++)
				{
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_Inputs = NULL;
					delete colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_p[0].m_Indices;
					free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_p);
					colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles[number_t].m_p = NULL;
				}
				free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles);
				colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh[0].m_Triangles = NULL;

				free(colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh);
				colladafile->m_GeometryLibrary[0].m_Geometries[geo].m_Mesh = NULL;
			}

			//free geometrices
			free (colladafile->m_GeometryLibrary[0].m_Geometries);
			colladafile->m_GeometryLibrary[0].m_Geometries = NULL;
		}

		//free geometry library
		if (colladafile->m_GeometryLibrary)
		{
			free (colladafile->m_GeometryLibrary);
			colladafile->m_GeometryLibrary = NULL;
		}
	}


}
